package color;

public class CLRConvert
{
	public static float[] ComputeRGBfromHSL(double h_prime, double C, double X)
	{
		float[] rgb = new float[3];
		if (h_prime < 0)
		{
			rgb[0] = rgb[1] = rgb[2] = 0;
		}
		
		else if (h_prime >= 0 && h_prime < 1)
		{
			rgb[0] = (float) C;
			rgb[1] = (float) X;
			rgb[2] = 0.0f;
		}
		
		else if (h_prime >= 1 && h_prime < 2)
		{
			rgb[0] = (float) X;
			rgb[1] = (float) C;
			rgb[2] = 0.0f;
		}
		
		else if (h_prime >= 2 && h_prime < 3)
		{
			rgb[0] =  0.0f;
			rgb[1] = (float) C;
			rgb[2] = (float) X;
		}
		
		else if (h_prime >= 3 && h_prime < 4)
		{
			rgb[0] =  0.0f;
			rgb[1] = (float) X;
			rgb[2] = (float) C;
		}
		
		else if (h_prime >= 4 && h_prime < 5)
		{
			rgb[0] = (float) X;
			rgb[1] = 0.0f;
			rgb[2] = (float) C;
		}
		
		else if (h_prime >= 5 && h_prime < 6)
		{
			rgb[0] = (float) C;
			rgb[1] = 0.0f;
			rgb[2] = (float) X;
		}
		
//		float m = (float) (0.5 - 0.5*C);
		float m = (float) (L - 0.5*C);
		rgb[0] += m;
		rgb[1] += m;
		rgb[2] += m;		
		
		// clamp the color range
		if (rgb[0] > 1.0f) rgb[0] = 1.0f;
		if (rgb[1] > 1.0f) rgb[1] = 1.0f;
		if (rgb[2] > 1.0f) rgb[2] = 1.0f;
		if (rgb[0] < 0.0f) rgb[0] = 0.0f;
		if (rgb[1] < 0.0f) rgb[1] = 0.0f;
		if (rgb[2] < 0.0f) rgb[2] = 0.0f;
		
		return rgb;
	}
	
	// strike is between 0 -> 360, let a color be between 0 -> 180, and the inverse will be from 180 -> 0
	// dip is between 0 -> 90, let it be the intensity of the color 
	public static float[] GetStrikeDipColor(double StrikeDeg, double DipDeg)
	{
		// assume a HSL color model, let hue be strike and s be dip
		double h_prime = StrikeDeg/60.0;
//		double C = DipDeg/90.0;
		double C = (1 - Math.abs(2*L - 1))*(DipDeg/90.0);
		double X = C*(1-Math.abs(h_prime % 2 - 1));
		return ComputeRGBfromHSL(h_prime, C, X);
	}
	
	// strike is between 0 -> 360, let a color be between 0 -> 180, and the inverse will be from 180 -> 0 
	public static float[] GetStrikeOnlyColor(double StrikeDeg)
	{
		// assume a HSL color model, let hue be strike and s be dip
		double h_prime = StrikeDeg/60.0;
//		double C = 1.0;
		double C = (1 - Math.abs(2*L - 1));
		double X = C*(1-Math.abs(h_prime % 2 - 1));
		return ComputeRGBfromHSL(h_prime, C, X);
	}

	static double L = 0.50; // ligthness component in the HSL color model
	// dip is between 0 -> 90, let it be the intensity of the color 
	public static float[] GetDipOnlyColor(double DipDeg)
	{
		// assume a HSL color model, let hue be strike and s be dip
		double h_prime = -1.0;
//		double C = (DipDeg/90.0);
		double C = (1 - Math.abs(2*L - 1))*(DipDeg/90.0);
		double X = C*(1-Math.abs(h_prime % 2 - 1));
		return ComputeRGBfromHSL(h_prime, C, X);
	}
	
	// given a wavelength, convert it to rgb where each color value ranges from 0 -> 255.
	// source ==> http://www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm
	public static float[] ConvertWaveLengthToRGB(double wavelength)
	{
		double R, G, B; R = G = B = 0.0;
		double factor = 0.0;
		
		if (wavelength >= 380 && wavelength <= 440)
		{
			R = -(wavelength - 440) / (440 - 380);
			G = 0.0;
			B = 1.0;
		}
		else if (wavelength > 440 && wavelength <= 489)
		{
			R = 0.0;
			G = (wavelength - 440) / (489 - 440);
			B = 1.0;			
		}
		else if (wavelength > 489 && wavelength <= 509)
		{
			R = 0.0;
			G = 1.0;
			B = -(wavelength - 509) / (509 - 489);			
		}
		else if (wavelength > 509 && wavelength <= 579)
		{
			R = (wavelength - 509) / (579 - 509);
			G = 1.0;
			B = 0.0;	
		}
		else if (wavelength > 579 && wavelength <= 644)
		{
			R = 1.0;
			G = -(wavelength - 644) / (644 - 579);
			B = 0.0;	
		}
		else if (wavelength > 644 && wavelength <= 780)
		{
			R = 1.0;
			G = 0.0;
			B = 0.0;	
		}
		
		// let the intensity fall off near the vision limits
		if (wavelength >= 380 && wavelength <= 419) factor = 0.3 + 0.7* (wavelength - 380.0) / (420.0 - 380.0);
		else if (wavelength > 419 && wavelength <= 700) factor = 1.0;
		else if (wavelength > 700 && wavelength <= 780) factor = 0.3 + 0.7*(780 - wavelength) / (780.0 - 700.0);
		
		float[] rgb = new float[3];
		rgb[0] = wavelengthAdjust(R, factor);
		rgb[1] = wavelengthAdjust(G, factor);
		rgb[2] = wavelengthAdjust(B, factor);
		return rgb;
	}
	
	// helper function for ConvertWaveLengthToRGB(double)
	private static float wavelengthAdjust(double color, double factor)
	{
		final double gamma = 0.80;
		final double maxIntensity = 255.0;
		
		if (color == 0.0) return 0.0f;
		return (float)(maxIntensity * Math.pow(color * factor, gamma));
	}
	
	// given a max and min where value is inbetween, return a wavelength representation
	// useful for converting a range of numbers to colors based on wavelength of light
	public static double ConvertToWaveLength(double min, double max, double value)
	{
		// the visible spectrum
//		final double minWaveLength = 350.0; // ultraviolet
//		final double maxWaveLength = 750.0; // infrared
		final double minWaveLength = 400.0; // blue
		final double maxWaveLength = 700.0; // red
		double wavelength = ((value - min) / (max - min)) * (maxWaveLength - minWaveLength) + minWaveLength;
		return wavelength;
	}
	
	// takes a range s.t. min=negative and max=positive and value lies inbetween
	// produces a color from hue 180->360 (cyan->red)
	public static float[] NegativeToPositiveScale(double min, double max, double value)
	{
		double percentage = (max-value)/(max-min); // find out the % of the length range value is between max and min
		double degrees = 180*percentage;

		double h_prime = (180+degrees)/60.0;
		double C = 1.0;
		double X = C*(1-Math.abs(h_prime % 2 - 1));

		return ComputeRGBfromHSL(h_prime, C, X);
	}
	
}
